﻿#region Copyright Info

// 
// Majesty of Omega - The next evolution of macro management space strategy
// 
// Copyright 2007-2009 André Claaßen
// 
// This file is protected by the terms and conditions of the
// Microsoft Community License (Ms-CL 1.1), a copy of which should
// have been distributed along with this software. If not,
// you may find the license information at the following URL:
// 
// http://www.microsoft.com/resources/sharedsource/licensingbasics/communitylicense.mspx

#endregion

#region

using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media.Animation;
using DesignByContract;
using Majesty_of_Omega.Logic.GameConfiguration;
using Majesty_of_Omega.Logic.Generator;

#endregion

namespace Majesty_of_Omega.GUI.Pages.Parts
{
    /// <summary>
    /// Event arguments for the LoadSaveGame Event. 
    /// </summary>
    public class LoadSaveGameEventArgs : RoutedEventArgs
    {
        private readonly SaveGameEntryPart.SaveGameEntryType _entryType;
        private readonly SaveGameManager.SaveGameInfo _saveGameInfo;

        /// <summary>
        /// Initializes a new instance of the <see cref="LoadSaveGameEventArgs"/> class.
        /// </summary>
        /// <param name="routedEvent">The routed event.</param>
        /// <param name="saveGameInfo">The save game info.</param>
        /// <param name="entryType">Type of the SaveGameEntry.</param>
        public LoadSaveGameEventArgs(RoutedEvent routedEvent, SaveGameManager.SaveGameInfo saveGameInfo,
                                     SaveGameEntryPart.SaveGameEntryType entryType)
            : base(routedEvent)
        {
            _entryType = entryType;
            _saveGameInfo = saveGameInfo;
        }

        /// <summary>
        /// Gets the type of the entry.
        /// </summary>
        /// <value>The type of the entry.</value>
        public SaveGameEntryPart.SaveGameEntryType entryType
        {
            get { return _entryType; }
        }

        /// <summary>
        /// Gets the save game info.
        /// </summary>
        /// <value>The save game info.</value>
        public SaveGameManager.SaveGameInfo SaveGameInfo
        {
            get { return _saveGameInfo; }
        }
    }

    /// <summary>
    /// This delegate handles the LoadSaveGameEvent
    /// </summary>
    public delegate void LoadSaveGameEventHandler(object sender, LoadSaveGameEventArgs e);

    /// <summary>
    /// Interaction logic for SaveGameEntryPart.xaml
    /// </summary>
    public partial class SaveGameEntryPart
    {
        #region Events

        /// <summary>
        /// Create a custom routed event by first registering a RoutedEventID
        /// This event uses the bubbling routing strategy
        /// </summary>
        public static readonly RoutedEvent LoadSaveGameEvent = EventManager.RegisterRoutedEvent(
            "LoadSaveGame", RoutingStrategy.Bubble, typeof (LoadSaveGameEventHandler), typeof (SaveGameEntryType));

        /// <summary>
        /// Occurs when [load save game].
        /// </summary>
        public event LoadSaveGameEventHandler LoadSaveGame
        {
            add { AddHandler(LoadSaveGameEvent, value); }
            remove { RemoveHandler(LoadSaveGameEvent, value); }
        }


        /// <summary>
        /// This method raises the LoadSaveGame event
        /// </summary>
        private void InvokeLoadSaveGameEvent()
        {
            RaiseEvent(new LoadSaveGameEventArgs(LoadSaveGameEvent, _saveGameInfo, _entryType));
        }

        /// <summary>
        /// Occurs when [next page].
        /// </summary>
        public event EventHandler NextPage;

        /// <summary>
        /// Invokes the next page Event.
        /// </summary>
        private void InvokeNextPageEvent()
        {
            EventHandler nextPageHandler = NextPage;
            if (nextPageHandler != null) nextPageHandler(this, new EventArgs());
        }

        /// <summary>
        /// Occurs when [prev page].
        /// </summary>
        public event EventHandler PrevPage;

        /// <summary>
        /// Invokes the prev page event.
        /// </summary>
        private void InvokePrevPageEvent()
        {
            EventHandler prevPageHandler = PrevPage;
            if (prevPageHandler != null) prevPageHandler(this, new EventArgs());
        }

        #endregion

        #region Types

        /// <summary>
        /// Save Game entry types
        /// </summary>
        public enum SaveGameEntryType
        {
            /// <summary>
            /// Normal filled game slot with a saved game.
            /// </summary>
            FilledGameEntry,
            /// <summary>
            /// Empty slot
            /// </summary>
            EmptyGameEntry,
            /// <summary>
            /// Next Page Button
            /// </summary>
            NextPage,
            /// <summary>
            /// Previous Page Button
            /// </summary>
            PrevPage
        }

        #endregion

        #region Private Fields

        /// <summary>
        /// The Entry-Type of this game slot
        /// </summary>
        private readonly SaveGameEntryType _entryType;

        /// <summary>
        /// The SaveGameInfo Object, which is associated with this Entry slot.
        /// </summary>
        private readonly SaveGameManager.SaveGameInfo _saveGameInfo;

        #endregion

        #region Dependency Properties

        /// <summary>
        /// Position Dependency Report
        /// </summary>
        public static readonly DependencyProperty PositionProperty =
            DependencyProperty.Register("Position", typeof (int), typeof (SaveGameEntryPart),
                                        new PropertyMetadata(-1, OnPositionPropertyChanged));


        /// <summary>
        /// Called when [position property changed].
        /// </summary>
        /// <param name="d">The d.</param>
        /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void OnPositionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var saveGameEntryPart = (SaveGameEntryPart) d;
            saveGameEntryPart.AdjustMotionAnimationToPosition((int) e.NewValue);
            saveGameEntryPart.AdjustBorderToPosition((int) e.NewValue);
        }

        #endregion

        /// <summary>
        /// Initialize a new instance of  <see cref="SaveGameEntryPart"/> class.
        /// </summary>
        /// <remarks>This Constructor is for Editing purposes of the SaveGameGridPart in Blend</remarks>
        public SaveGameEntryPart()
        {
            InitializeComponent();
            EntryGrid.DataContext = TestDataGenerator.TestSaveGameInfo;
            _entryType = SaveGameEntryType.FilledGameEntry;
            _saveGameInfo = null;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SaveGameEntryPart"/> class.
        /// </summary>
        /// <param name="entryType">Type of the entry.</param>
        /// <param name="position">The position.</param>
        /// <param name="saveGameInfo">The save game info.</param>
        public SaveGameEntryPart(SaveGameEntryType entryType, int position, SaveGameManager.SaveGameInfo saveGameInfo)
        {
            InitializeComponent();
            _entryType = entryType;
            Position = position;
            EntryGrid.DataContext = saveGameInfo;
            EmptyTypeTextBlock.Visibility = Visibility.Visible;
            switch (_entryType)
            {
                case SaveGameEntryType.EmptyGameEntry:
                    Require.IsNull(saveGameInfo);
                    EmptyTypeTextBlock.Text = "(Empty Slot)";
                    break;

                case SaveGameEntryType.FilledGameEntry:
                    Require.IsNotNull(saveGameInfo);
                    break;

                case SaveGameEntryType.NextPage:
                    Require.IsNull(saveGameInfo);
                    EmptyTypeTextBlock.Text = "Next Page";
                    break;

                case SaveGameEntryType.PrevPage:
                    Require.IsNull(saveGameInfo);
                    EmptyTypeTextBlock.Text = "Previous Page";
                    break;

                default:
                    Require.ThrowException("Unknown Save game entry type: " + entryType);
                    break;
            }
        }

        /// <summary>
        /// Gets or sets the position of the SaveGameEntryPart in the Save Game Grid.
        /// </summary>
        /// <value>The position.</value>
        public int Position
        {
            get { return (int) GetValue(PositionProperty); }
            set { SetValue(PositionProperty, value); }
        }

        /// <summary>
        /// Adjusts the motion animation to position.
        /// </summary>
        /// <param name="position">The position.</param>
        private void AdjustMotionAnimationToPosition(int position)
        {
            AdjustLoadAnimation(position);
            AdjustUnloadAnimation(position);
        }

        /// <summary>
        /// Adjusts the load animation. The number of the position delays the end of the animation
        /// </summary>
        /// <param name="position">The position.</param>
        private void AdjustLoadAnimation(int position)
        {
            MotionAnimationLoaded.KeyFrames.Clear();
            MotionAnimationLoaded.KeyFrames.Add(new SplineDoubleKeyFrame(position%2 == 0 ? -1000 : 1000,
                                                                         KeyTime.FromTimeSpan(new TimeSpan(0, 0, 0, 0))));
            MotionAnimationLoaded.KeyFrames.Add(new SplineDoubleKeyFrame(0,
                                                                         KeyTime.FromTimeSpan(new TimeSpan(0, 0, 0, 0,
                                                                                                           (position +
                                                                                                            10)*50))));
        }

        /// <summary>
        /// Adjusts the unload animation. The number of the position delays the start of the animation
        /// </summary>
        /// <param name="position">The position.</param>
        private void AdjustUnloadAnimation(int position)
        {
            MotionAnimationUnloaded.KeyFrames.Clear();
            MotionAnimationUnloaded.KeyFrames.Add(new SplineDoubleKeyFrame(0,
                                                                           KeyTime.FromTimeSpan(new TimeSpan(0, 0, 0, 0,
                                                                                                             position*50))));
            MotionAnimationUnloaded.KeyFrames.Add(new SplineDoubleKeyFrame(position%2 == 0 ? -1000 : 1000,
                                                                           KeyTime.FromTimeSpan(new TimeSpan(0, 0, 0, 2))));
        }

        /// <summary>
        /// Adjusts the border to position. the left side entries have other rounded borders
        /// </summary>
        /// <param name="position">The position.</param>
        private void AdjustBorderToPosition(int position)
        {
            EntryBorder.CornerRadius = position%2 == 0 ? new CornerRadius(16, 0, 0, 0) : new CornerRadius(0, 0, 16, 0);
        }

        /// <summary>
        /// Starts the unload animation.
        /// </summary>
        public void StartUnloadAnimation()
        {
            UnloadAnimationStoryBoard.Begin(UserControl);
        }

        /// <summary>
        /// Handles the MouseLeftButtonUp event of the EntryBorder control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>
        private void EntryBorder_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            switch (_entryType)
            {
                case SaveGameEntryType.EmptyGameEntry:
                    InvokeLoadSaveGameEvent();
                    break;
                case SaveGameEntryType.NextPage:
                    InvokeNextPageEvent();
                    break;
                case SaveGameEntryType.PrevPage:
                    InvokePrevPageEvent();
                    break;
                default:
                    break;
            }
        }
    }
}